<template>
  <div>
    <el-card shadow="always" :body-style="{ padding: '20px' }">
      <el-form label-width="80px">
        <el-form-item label="SPU名称">
          <el-input placeholder="SPU名称" v-model="spuInfo.spuName"></el-input>
        </el-form-item>
        <el-form-item label="品牌">
          <el-select placeholder="请选择" v-model="(spuInfo.tmId as number)">
            <el-option
              v-for="item in trademarkList"
              :key="item.id"
              :label="item.tmName"
              :value="(item.id as number)"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="SPU描述">
          <el-input
            placeholder="SPU描述"
            type="textarea"
            v-model="spuInfo.description"
          ></el-input>
        </el-form-item>
        <el-form-item label="SPU图片">
          <el-upload
            v-model:file-list="fileList"
            :action="`${baseUrl}/admin/product/upload`"
            list-type="picture-card"
            :on-success="handleAddPicSuccess"
          >
            <el-icon><ele-Plus /></el-icon>
          </el-upload>
        </el-form-item>
        <el-form-item label="销售属性">
          <el-select placeholder="请选择" v-model="saleAttrSelect">
            <el-option
              v-for="item in unSelectAttr"
              :key="item.id"
              :label="item.name"
              :value="`${item.id}:${item.name}`"
            >
            </el-option>
          </el-select>
          <el-button type="primary" size="default" @click="addSaleAttr"
            >添加销售属性</el-button
          >
        </el-form-item>
        <el-form-item>
          <el-table :data="saleAttrSelectList" border stripe>
            <el-table-column type="index" width="80" label="序号" />
            <el-table-column label="属性名" prop="saleAttrName">
            </el-table-column>
            <el-table-column label="属性值名称列表">
              <template v-slot="{ row }">
                <!-- 遍历当前row的属性值列表生成tag -->
                <el-tag
                  v-for="(item, index) in row.spuSaleAttrValueList"
                  :key="item.saleAttrValueName"
                  type="danger"
                  size="small"
                  closable
                  @close="deleteTag(row.spuSaleAttrValueList, index)"
                  >{{ item.saleAttrValueName }}</el-tag
                >
                <!-- input和button条件渲染 -->
                <el-input
                  v-if="row.isEdit"
                  placeholder=""
                  size="small"
                  @blur="toLook(row)"
                  v-model="row.inputValue"
                  ref="inputRef"
                ></el-input>
                <el-button
                  v-else
                  type="primary"
                  size="small"
                  @click="toEdit(row)"
                  icon="ele-Plus"
                  >添加销售属性值</el-button
                >
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <template v-slot="{ $index }">
                <el-popconfirm
                  title="是否确认删除?"
                  @confirm="deleteSaleAttr($index)"
                >
                  <template #reference>
                    <el-button type="danger" size="small" icon="ele-Delete"
                      >删除</el-button
                    >
                  </template>
                </el-popconfirm>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="default" @click="save"
            >保存</el-button
          >
          <el-button size="default" @click="cancel">取消</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script lang="ts">
  import { defineComponent } from "vue"

  export default defineComponent({
    name: "SpuInfo",
  })
</script>

<script setup lang="ts">
  import { storeToRefs } from "pinia"
  import { ref, onMounted, computed, nextTick } from "vue"
  import { ElMessage, type UploadUserFile } from "element-plus"
  import { reqAllTrademark } from "@/api/trademark"
  import {
    reqAllSaleAttrList,
    reqAddSpu,
    reqSaleAttrListBySpuId,
    reqImageListBySpuId,
    reqUpdateSpu,
  } from "@/api/spu"
  import type { trademarkLitsType } from "@/api/trademark"
  import type {
    saleAttrListType,
    spuSaleAttrListType,
    spuInfoItemType,
    spuSaleAttrItemType,
    spuSaleAttrValueListType,
    spuImageListType,
  } from "@/api/spu"
  import useCategoryListState from "@/stores/category"
  import { cloneDeep } from "lodash"

  //收集公共请求前缀，从环境变量中读取
  const baseUrl = import.meta.env.VITE_API_URL

  //定义用来收集图片上传的图片列表
  const fileList = ref<UploadUserFile[]>([])
  //获取categoryStore数据对象
  const categoryStore = useCategoryListState()

  //从store中获取当前的category3Id
  const { category3Id } = storeToRefs(categoryStore)

  //初始化保存所有品牌的数据
  const trademarkList = ref<trademarkLitsType>([])
  //初始化保存所有销售属性的数据
  const saleAttrList = ref<saleAttrListType>([])

  //定义一个数据 保存销售属性双向绑定的收集的字符串(包含id和name两个值)
  const saleAttrSelect = ref("")
  //定义一个数据用来收集销售属性列表
  const saleAttrSelectList = ref<spuSaleAttrListType>([])

  //接受父组件传递过来的spuInfo数据(可能是新增时的初始化数据,也可能是修改时的回填数据)
  const props = defineProps<{
    spuInfo: spuInfoItemType
  }>()

  //当前组件就不需要初始化spuInfo,而是接受来自父组件传递的props即可
  //因为spuInfo和当前的模板经常数据绑定,为了不修改props,我们可以把props深拷贝一份,自己保存使用
  const spuInfo = ref<spuInfoItemType>(cloneDeep(props.spuInfo))

  //封装所有品牌的请求和所有销售属性的请求(供新增spu时获取完整选项列表的时候使用)
  const getAllTrademark = async () => {
    const result = await reqAllTrademark()
    trademarkList.value = result
  }

  const getAllSaleAttrList = async () => {
    const result = await reqAllSaleAttrList()
    saleAttrList.value = result
  }

  //封装点击修改时候所需要的图片列表和销售属性列表的请求
  const getUpdateSaleAttrList = async () => {
    const result = await reqSaleAttrListBySpuId(spuInfo.value.id as number)
    saleAttrSelectList.value = result
  }

  const getUpdateImageList = async () => {
    const result = await reqImageListBySpuId(spuInfo.value.id as number)
    result.forEach((item) => {
      fileList.value.push({
        name: item.imgName,
        url: item.imgUrl,
      })
    })
  }

  //初始化发送所有品牌和所有销售属性请求
  //如果是新增则发送两个请求:所有品牌和所有销售属性请求
  //如果是修改(修改时有id)则发送四个请求:所有品牌和所有销售属性请求和当前选中的spuId的销售属性列表和当前spuId的图片列表
  onMounted(() => {
    getAllTrademark()
    getAllSaleAttrList()
    if (spuInfo.value.id) {
      getUpdateSaleAttrList()
      getUpdateImageList()
    }
  })

  //图片上传成功之后的回调函数
  const handleAddPicSuccess = (response: any, a: any, b: any) => {
    //参数1：当前图片上传请求的响应
    //参数2：当前图片的详细信息
    //参数3：当前上传成功后，完整的图片列表的数组
    // console.log(b)
    fileList.value = b
  }

  //点击添加销售属性按钮事件回调函数
  const addSaleAttr = () => {
    //判断当前销售属性下拉选框是否有收集，如果有收集才能添加销售属性
    if (!saleAttrSelect.value) {
      return ElMessage.error("销售属性为空！")
    }
    //解构收集到的销售属性值和id
    const [baseSaleAttrId, saleAttrName] = saleAttrSelect.value.split(":")
    //把当前收集到的销售属性信息插入到已收集的销售属性列表中，最终进行展示
    saleAttrSelectList.value.push({
      baseSaleAttrId: +baseSaleAttrId, //解构出来是一个字符串,需要转为number
      saleAttrName,
      spuSaleAttrValueList: [],
      isEdit: false, //模式
      inputValue: "", //用来收集当前销售属性中 的 添加销售属性值时input的数据
    })

    //添加完销售属性后清空输入框
    saleAttrSelect.value = ""
  }

  //计算属性,计算全部销售属性中还有哪些销售属性没有被选中
  const unSelectAttr = computed(() => {
    //saleAttrList:完整的销售属性列表
    //saleAttrSelectList:已经收集到的销售属性列表
    //最后我们希望的结果是,删除完成的销售属性列表中 已经被收集到的值,保存未被收集的选项
    return saleAttrList.value.filter((saleAttr) => {
      //遍历每一个完整的值,判断每一个 是否有和已经选中的名称相同,如果有,则返回false,如果没有则返回true
      return !saleAttrSelectList.value.some((saleAttrSelect) => {
        return saleAttrSelect.saleAttrName === saleAttr.name
      })
    })
  })

  //初始化数据保存编辑模式的input元素
  const inputRef = ref()

  //点击添加销售属性值按钮,切换编辑模式的事件回调函数
  const toEdit = (row: spuSaleAttrItemType) => {
    row.isEdit = true
    //自动获取焦点
    nextTick(() => {
      inputRef.value.focus()
    })
  }

  //当添加销售属性值的input框失去焦点的时候，切换查看模式的事件回调函数
  const toLook = (row: spuSaleAttrItemType) => {
    //首先切换到查看模式
    row.isEdit = false
    if (!row.inputValue) {
      return ElMessage.error("输入的销售属性值不能为空！")
    }

    //判断输入的内容是否重复
    const isRepeat = row.spuSaleAttrValueList.some((item) => {
      return item.saleAttrValueName === row.inputValue
    })
    if (isRepeat) {
      //如果输入的内容有重复的，则清空inputValue的数据
      row.inputValue = ""
      return ElMessage.error("输入的销售属性值不能重复！")
    }

    //把当前输入的内容整理一下,向当前row中添加新的销售属性值数据
    row.spuSaleAttrValueList.push({
      baseSaleAttrId: row.baseSaleAttrId, //当前spu销售属性的id
      saleAttrName: row.saleAttrName, //当前销售属性值所在的销售属性名称
      saleAttrValueName: row.inputValue as string, //当前spu销售属性值的名字
    })
    //添加完毕后清空输入框
    row.inputValue = ""
  }

  //删除某一个tag的事件回调函数
  const deleteTag = (list: spuSaleAttrValueListType, index: number) => {
    list.splice(index, 1)
  }

  const emit = defineEmits<{
    (event: "changeShowIndex", index: number): void
  }>()

  //点击保存按钮后提交
  const save = async () => {
    //整理参数1:图片列表
    //如果是修改的话 spuInfo的spuImageList值是空,无法使用push方法,所以先给一个初始值
    spuInfo.value.spuImageList = []
    //因为修改的时候有回填数据,回填数据的格式和新上传数据的格式是不一致的,所以需要判断然后再整理参数
    fileList.value.forEach((item) => {
      ;(spuInfo.value.spuImageList as spuImageListType).push({
        imgName: item.name, // 图片的名称
        imgUrl: item.response ? (item.response as any).data : item.url, // 图片的地址
      })
    })
    //整理参数2：销售属性列表
    spuInfo.value.spuSaleAttrList = saleAttrSelectList.value

    //提交发起请求//提交的时候判断当前是新增还是修改(使用id判断)
    if (spuInfo.value.id) {
      await reqUpdateSpu(spuInfo.value)
    } else {
      await reqAddSpu(spuInfo.value)
    }

    //切换到spuList
    emit("changeShowIndex", 1)
  }

  //点击取消按钮切换到spuList
  const cancel = () => {
    emit("changeShowIndex", 1)
  }

  //删除指定的销售属性
  const deleteSaleAttr = (index: number) => {
    saleAttrSelectList.value.splice(index, 1)
    ElMessage.success("删除销售属性成功！")
  }
</script>

<style scoped lang="scss"></style>
